package states;

import hypeerweb.Node;

/*public abstract class NodeState
 {
 public static NodeState getNodeState(int id)
 {
 switch (id)
 {
 case 0:
 return StandardNodeState.getSingleton();
 case 1:
 return UpPointingNodeState.getSingleton();
 case 2:
 return DownPointingNodeState.getSingleton();
 case 3:
 return HypercubeCapState.getSingleton();
 case 4:
 return TerminalNodeState.getSingleton();
 default:
 return null;
 }

 }

 public abstract String toString();

 // Add any methods that need to be state-dependent below, then implement in inherited classes
 // public abstract Node findLastNode(Node lower, Node higher)
 }*/

public enum NodeState {
	StandardNodeState {
		int STATE_ID = 0;

		@Override
		public void findLastNode(Node node) {
			UpPointingNodeState.findLastNode(node);
		}

		@Override
		public String toString() {
			return "Standard Node State";
		}
	},
	UpPointingNodeState {
		public int STATE_ID = 1;

		@Override
		public void findLastNode(Node node) {
			if (deletionPoint.getWebId().getParentsValue() + 1 == insertionPoint.getId()) {
				return;
			}

			Node edge = node.getLargestISN();
			if (edge.getId() > deletionPoint.getId()) {
				deletionPoint = edge;
				edge.findInsertionPoint();
			} else {
				Node childlessNeighbor = node.getSmallestNeighborWithoutChild();
				insertionPoint = childlessNeighbor;
				childlessNeighbor.findInsertionPoint();
			}
		}

		@Override
		public String toString() {
			return "Up Pointing State";
		}
	},
	DownPointingNodeState {
		public int STATE_ID = 2;

		@Override
		public void findLastNode(Node node) {}

		@Override
		public String toString() {
			return "Down Pointing Node State";
		}
	},
	HypercubeCapState {
		public int STATE_ID = 3;

		@Override
		public void findLastNode(Node node) {
			insertionPoint = node.getFold();
			deletionPoint = node;
		}

		public Node findTerminalNode(Node node) {
			return node;
		}

		@Override
		public String toString() {
			return "Hypercube Cap State";
		}
	},
	TerminalNodeState {
		public int STATE_ID = 4;

		@Override
		public void findLastNode(Node node) {
			if (deletionPoint.getWebId().getParentsValue() + 1 == deletionPoint.getId()) {
				return;
			}

			Node surrNeighbor = node.getSmallestSurrNeighbor();
			insertionPoint = surrNeighbor;
			surrNeighbor.findInsertionPoint();
		}

		public Node findTerminalNode(Node node) {
			return node;
		}

		@Override
		public String toString() {
			return "Terminal Node State";
		}
	};

	public int STATE_ID;
	
	//This is the insertion point once the algorithm is done
	private static Node insertionPoint;
	//This is the deletion point once the algorithm is done
	private static Node deletionPoint;

	public abstract void findLastNode(Node node);
	
	public static Node getInsertionPoint() {
		return insertionPoint;
	}
	
	public static Node getDeletionPoint() {
		return deletionPoint;
	}
	
	public void findInsertionAndDeletionPoints(Node node, Node lower, Node higher) {
		deletionPoint = lower;
		insertionPoint = higher;
		this.findLastNode(node);
	}

	public Node findTerminalNode(Node node) {
		Node next = node.getLargestConnection();
		return next.findTerminalNode();
	}

	public int getNodeState() {
		return this.STATE_ID;
	}

	public static NodeState getNodeState(int state) {
		switch (state) {
		case 0:
			return StandardNodeState;
		case 1:
			return UpPointingNodeState;
		case 2:
			return DownPointingNodeState;
		case 3:
			return HypercubeCapState;
		case 4:
			return TerminalNodeState;
		default:
			return null;
		}
	}

	public abstract String toString();
}
